<?php

/**
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; version 3 of the License.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 */

/**
 * File(s) upload.
 * Required DirectoryHandler and StringHandler util from LISA framework
 * @package Util
 * @author Somlyai Dezső
 * @version 0.2.3
 */
namespace Util; 

class FileUpload {

	/**
	 * Uploaded file(s).
	 * @access protected
	 * @var array
	 */
	protected $_uploadedFiles = array();

	/**
	 * File(s) to upload generated from $_FILES variable.
	 * @access protected 
	 * @var array
	 */
	protected $_files = array();

	/**
	 * Destination path of uploaded file(s).
	 * @acces protected
	 * @var string
	 */
	protected $_path;

	/**
	 * Allowed file extensions.
	 * @access public
	 * @var mixed
	 */
	public $allowedExtensions = null;

	/**
	 * Generated safe filename.
	 * @access public
	 * @var bool
	 */
	public $safeFilename = true;

	/**
	 * Replace file path
	 * @access public
	 * @var string
	 */
	public $saveToPath = null;

	/**
	 * Safe filename character settings
	 * @access protected
	 * @var string
	 */
	protected $_charSet;

	/**
	 * Constructor.
	 * @access public
	 * @param string $fieldsName
	 * @param string $path
	 * @param mixed $allowedExtensions
	 * @param string $charset
	 * @throws Exception
	 * @return void
	 */
	public function __construct($fieldsName, $path, $allowedExtensions = null, $charset = null) {
		if (!isset($_FILES[$fieldsName])) {
			throw new \Exception("File not exists!");
		}
		if (is_array($allowedExtensions)) {
			foreach ($allowedExtensions as $key => $value) {
				$this->allowedExtensions[$key] = ltrim($value, ".");
			}
		} elseif (!is_null($allowedExtensions)) {
			$this->allowedExtensions = array(ltrim($this->allowedExtensions, "."));
		}

		$this->_path = $path;
		$this->_charSet = $charset;

		if (is_array($_FILES[$fieldsName]["name"])) {
			foreach ($_FILES[$fieldsName]["name"] as $key=>$file) {
                if (!empty($file)) {
    				$this->_files[$key] = array(
    					"name" => $this->safeFilename == true ? \Util\StringHandler::safeFileName($file, $this->_charSet) : $file,
    					"type" => $_FILES[$fieldsName]["type"][$key],
    					"tmp_name" => $_FILES[$fieldsName]["tmp_name"][$key],
    					"size" => $_FILES[$fieldsName]["size"][$key],
    					"error" => $_FILES[$fieldsName]["error"][$key]
    				);
    			}
			}
		} else {
			$this->_files[] = $_FILES[$fieldsName];
			$this->_files[0]["name"] = $this->safeFilename == true ? \Util\StringHandler::safeFileName($this->_files[0]["name"], $this->_charSet) : $this->_files[0]["name"];
		}

	}

	/**
	 * Factory method of Upload
	 * @access public
	 * static
	 * @param string $fieldsName
	 * @param string $path
	 * @param mixed $allowedExtensions
	 * @param string $charset
	 * @return Upload 
	 */
	public static function init($fieldsName, $path, $allowedExtensions = null, $charset = null) {
		return new self($fieldsName, $path, $allowedExtensions, $charset);
	}
	
	/**
	 * Factory method of Upload
	 * @access public
	 * static
	 * @param string $fieldsName
	 * @param string $path
	 * @param mixed $allowedExtensions
	 * @param string $charset
	 * @return array of $_files
	 */
	public static function upload($fieldsName, $path, $allowedExtensions = null, $charset = null) {
		$self = self::init($fieldsName, $path, $allowedExtensions, $charset);
		return $self->send();
	}
	
	/**
	 * List of successfully uploaded file(s).
	 * @access public
	 * @return array 
	 */
	public function getSucces() {
		return $this->getFiles(true);
	}

	/**
	 * List of not uploaded file(s).
	 * @access public
	 * @return array
	 */
	public function getErrors() {
		return $this->getFiles(false);
	}

	/**
	 * Commit upload.
	 * @access public
	 * @return array
	 */
	public function send() {
		return $this->_upload();
	}

	/**
	 * List of all file(s).
	 * @access public
	 * @param bool $access
	 * @return array
	 */
	public function getFiles($access = null) {

		if (is_null($access)) {
			$out = $this->_files;
		} else {
			$out = array();

			foreach ($this->_files as $key => $value) {
				if ($access === false && $value["error"] !== UPLOAD_ERR_OK) {
					$out[] = $value;
				} elseif ($access === true && $value["error"] === UPLOAD_ERR_OK) {
					$out[] = $value;
				}
			}
		}

		return $out;
	}

	/**
	 * Copy files to other directory.
	 * @access protected
	 * @param string $from
	 * @param string $to
	 * @return boolean
	 */
	protected function _copyTo($from, $to) {
		return copy($from, $to);
	}

	/**
	 * Upload files.
	 * @access protected
	 * @return void
	 */
	protected function _upload() {
		$path = $this->_checkPath($this->_path);

		foreach ($this->_files as $key => &$file) {
			$this->_checkExtensions($file);
			if ($file["error"] === UPLOAD_ERR_OK) {

				$file["name"] = \Util\DirectoryHandler::getUniqueFileName($path, $file["name"]);

				if (move_uploaded_file($file["tmp_name"], $path . $file["name"])) {
					if (!is_null($this->saveToPath)) {
						if (!$this->_copyTo($path . $file["name"], $this->_checkPath($this->saveToPath) . $file["name"])) {
							$file["error"] = "UPLOAD_ERR_COPY";
						}
					}
				} else {
					$file["error"] = "UPLOAD_ERR_UNKNOWN";
				}
			}
		}
		return $this->_files;
	}

	/**
	 * Check or create upload directory.
	 * @access protected
	 * @param string $path
	 * @return string
	 */
	protected function _checkPath($path = null) {
		if (!is_null($path)) {
			$path = rtrim($path, "/") . "/";
			\Util\DirectoryHandler::mkdirRecursive($path, 0774);
		}

		return $path;
	}

	/**
	 * Check Allowed file extensions.
	 * @access protected
	 * @return void
	 */
	protected function _checkExtensions(&$file) {
		if (!is_null($this->allowedExtensions)) {

			$ext = ltrim(\Util\StringHandler::localeToCommonLower(strrchr($file["name"], "."), $this->_charSet), ".");

			if (!in_array($ext, $this->allowedExtensions)) {
				$file["error"] = "UPLOAD_ERR_EXT";
			}
		}
	}

}

?>
